package com.angel.webapp.servlets;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.angel.architecture.exceptions.NonBusinessException;
import com.angel.common.helpers.StringHelper;
import com.angel.common.keyValue.KeyValueResult;
import com.angel.webapp.file.FileInformation;

/**
 * @author William
 * @since 13/August/2009
 */
public abstract class DownloadServlet extends BaseAngelServlet{

	private static final Logger LOGGER = Logger.getLogger(DownloadServlet.class);
	
	private static final long serialVersionUID = 4401660661793903163L;

	protected static final String HEADER_KEY_CACHE_CONTROL = "Cache-Control";

    protected static final String HEADER_KEY_CONTENT_DISPOSITION = "Content-Disposition";

    protected static final String CONTENT_TYPE_NAME = "Cache-Control";

    protected static final String HEADER_VALUE_MAX_AGE = "max-age=" + (60 * 60 * 24);

    protected static final String HEADER_VALUE_ATTACHMENT= "attachment;filename=";

    protected static final String DEFAULT_SEPARATOR_PARAMETERS = "*";
    
    protected static final String REQ_PARAMETER_SEPARATOR_PARAMETERS = "separatorParameters";
    
    protected static final String RE_INITIALIZE_CONFIGURATION_PARAMETERS = "reInitialize";

    protected abstract FileInformation doProcess(KeyValueResult keyValueResult, final HttpServletRequest request, final HttpServletResponse response);

    @Override
    protected void process(KeyValueResult keyValueResult, final HttpServletRequest request, final HttpServletResponse response) {
    	try {
	        LOGGER.info("Checking parameters to execute export process.");
	        this.doCheckParameters(keyValueResult);
	        
	        LOGGER.info("Executing export process.");
	        FileInformation downloadFileInformation = this.doProcess(keyValueResult, request, response);
	
	        LOGGER.info("Building output stream to download export file.");
	        this.buildOutputStream(downloadFileInformation, request, response);
    	} catch (Throwable e) {
    		throw new NonBusinessException("Error occured during exporting process. It was caused by: " + e.getMessage(), e);
		}
    }

    protected void buildOutputStream(FileInformation downloadFileInformation, final HttpServletRequest request, final HttpServletResponse response){
    	String fullFileName = this.buildFileName(downloadFileInformation);
    	fullFileName = StringHelper.replaceAll(fullFileName, " ", "");
        String contentType = downloadFileInformation.getContentType();
        final InputStream in = downloadFileInformation.getInputStream();
        int length = downloadFileInformation.getLength();

        response.setHeader(HEADER_KEY_CACHE_CONTROL, HEADER_VALUE_MAX_AGE);
        response.setContentType(contentType);
        response.addHeader(HEADER_KEY_CONTENT_DISPOSITION, HEADER_VALUE_ATTACHMENT + fullFileName);

        if(length > 0){
            response.setContentLength(length);
        }

        OutputStream out = null;
        try {
            out = response.getOutputStream();
            byte[] buf = new byte[1024];
            int count;
            int totalLength = 0;
            while ((count = in.read(buf)) >= 0) {
                out.write(buf, 0, count);
                totalLength += count;
            }
            response.setContentLength(totalLength);
            out.flush();
        } catch (IOException e) {
            throw new NonBusinessException("Error during building output stream.", e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) { 
            	throw new NonBusinessException("Error during closing input/output stream.", e);
            }
        }
    }

    private String buildFileName(FileInformation fileInformation) {
		return StringHelper.isEmpty(fileInformation.getFileName()) ? "attachment" : fileInformation.getFileName();
	}

	/** Check request parameters to can make export process. If parameters necessaries are not present in the request, it throws
     * a NonBusinessException.
     *
     * @param keyValueResult
     * @see com.angel.arquitectura.exception.NonBusinessException
     */
    protected void doCheckParameters(KeyValueResult keyValueResult) {
        if(!keyValueResult.hasResult()){
            String errorMessage = "Parameters are not added to request. ";
            throw new NonBusinessException(errorMessage);
        }
    }
}